<?php

/*

Source Code: http://www.php-class.buss.hk/php-reverse-proxy/prp-source-code

*/

class PhpReverseProxy{
	
        public $publicBaseURL;
        public $outsideHeaders;
        public $XRequestedWith;
        
        public $sendPost;
        
        
        public $port,$host,$content,$forward_path,$content_type,$user_agent,
		$XFF,$request_method,$IMS,$cacheTime,$cookie,$authorization;
	private $http_code,$lastModified,$version,$resultHeader;
        
        const chunkSize = 10000;
	
	function __construct(){
            
		$this->version="PHP Reverse Proxy (PRP) 1.0";
		$this->port="8080";
		$this->host="127.0.0.1";
		$this->content="";
		$this->forward_path="";
		$this->path="";
		$this->content_type="";
		$this->user_agent="";
		$this->http_code="";
		$this->XFF="";
		$this->request_method="GET";
		$this->IMS=false;	// If-Modified-Since
		$this->cacheTime=72000;
		$this->lastModified=gmdate("D, d M Y H:i:s",time()-72000)." GMT";
		$this->cookie="";
                $this->XRequestedWith = "";
		$this->authorization = ""; //authorization header, needed for sending login OK
	}
	function translateURL($serverName) {
		$this->path=$this->forward_path.$_SERVER['REQUEST_URI'];
		if($_SERVER['QUERY_STRING']=="")
			return $this->translateServer($serverName).$this->path;
		else
		return $this->translateServer($ServerName).$this->path."?".$_SERVER['QUERY_STRING'];
	}
	function translateServer($serverName) {
		$s = empty($_SERVER["HTTPS"]) ? ''
			: ($_SERVER["HTTPS"] == "on") ? "s"
			: "";
		$protocol = $this->left(strtolower($_SERVER["SERVER_PROTOCOL"]), "/").$s;
		if($this->port=="") 
			return $protocol."://".$serverName;
		else
			return $protocol."://".$serverName.":".$port;
	}
	function left($s1, $s2) {
		return substr($s1, 0, strpos($s1, $s2));
	}
	function preConnect(){
		$this->user_agent=$_SERVER['HTTP_USER_AGENT'];
		$this->request_method=$_SERVER['REQUEST_METHOD'];
		$tempCookie="";
		foreach ($_COOKIE as $i => $value) {
			$tempCookie=$tempCookie." $i=$_COOKIE[$i];";
		}
		$this->cookie=$tempCookie;
		if(empty($_SERVER['HTTP_X_FORWARDED_FOR'])){
			$this->XFF=$_SERVER['REMOTE_ADDR'];
		} else {
			$this->XFF=$_SERVER['HTTP_X_FORWARDED_FOR'].", ".$_SERVER['REMOTE_ADDR'];
		}
                
	}
	function connect(){
		if(empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])){
			$this->preConnect();
			$ch=curl_init();
			if($this->request_method=="POST"){
				curl_setopt($ch, CURLOPT_POST,1);
                                
                                $postData = array();
                                $filePost = false;
                                
                                if(count($_FILES)>0){
                                    if(!is_writable("uploads/")){
                                        die('You cannot upload to the specified directory, please CHMOD it to 777.');
                                    }
                                    
                                    foreach($_FILES as $key => $fileArray){ 
                                        copy($fileArray["tmp_name"], "uploads/" . $fileArray["name"]);
                                        //$proxyLocation = $this->publicBaseURL."/uploads/" . $fileArray["name"];
                                        $proxyLocation = "@uploads/" . $fileArray["name"];
                                        $postData = array($key => $proxyLocation);
                                        $filePost = true;
                                    }
                                }
                                
                                foreach($_POST as $key => $value){
                                    if(!is_array($value)){
                                        $postData[$key] = $value;
                                    }
                                    else{
                                        $postData[$key] = serialize($value);
                                    }
                                }
                                
                                if(!$filePost){
                                    //collabpse into url encoded text
                                    //$postData = http_build_query($postData);
                                   $postString = "";
                                   $firstLoop = true;
                                   foreach($postData as $key => $value){
                                    $parameterItem = urlencode($key)."=".urlencode($value);
                                    if($firstLoop){
                                        $postString .=  $parameterItem;
                                    }
                                    else{
                                        $postString .=  "&".$parameterItem;
                                    }
                                    $firstLoop = false; 
                                   }
                                   $postData = $postString;
                                }
                                
                                //echo print_r($postData);
                                
                                //curl_setopt($ch, CURLOPT_VERBOSE, 0);
                                //curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                                //curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible;)");
                                $this->sendPost =  $postData;
                                curl_setopt($ch, CURLOPT_POSTFIELDS,$postData);
                                //curl_setopt($ch, CURLOPT_POSTFIELDS,file_get_contents($proxyLocation));
                                //curl_setopt($ch, CURLOPT_POSTFIELDS,file_get_contents("php://input"));
                        }
                        
                        //gets rid of mulitple ? in URL
                        $translateURL =  $this->translateURL($this->host);
                        if(substr_count($translateURL, "?")>1){
                            $firstPos = strpos($translateURL, "?", 0);
                            $secondPos = strpos($translateURL, "?", $firstPos + 1);
                            $translateURL = substr($translateURL, 0, $secondPos);
                        }
                        
			curl_setopt($ch,CURLOPT_URL,$translateURL);
			
                        
                        $proxyHeaders = array("X-Forwarded-For: ".$this->XFF,
					"User-Agent: ".$this->user_agent);
                        
                        if(strlen($this->XRequestedWith)>1){
                            $proxyHeaders[] = "X-Requested-With: ".$this->XRequestedWith;
                            //echo print_r($proxyHeaders);
                        }
                        
                        curl_setopt($ch,CURLOPT_HTTPHEADER, $proxyHeaders);
                        
                        if($this->cookie!=""){
				curl_setopt($ch,CURLOPT_COOKIE,$this->cookie);
			}
			curl_setopt($ch,CURLOPT_FOLLOWLOCATION,true); 
			curl_setopt($ch,CURLOPT_AUTOREFERER,true); 
			curl_setopt($ch,CURLOPT_HEADER,true);
			curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
                       
                        
                        
			$output=curl_exec($ch);
			$info	= curl_getinfo( $ch );
			curl_close($ch);
			$this->postConnect($info,$output);
		}else {
			$this->lastModified=$_SERVER['HTTP_IF_MODIFIED_SINCE'];
			$this->IMS=true;
		}
	}
	function postConnect($info,$output){
		$this->content_type=$info["content_type"];
		$this->http_code=$info['http_code'];
		if(!empty($info['last_modified'])){
			$this->lastModified=$info['last_modified'];
		}
		$this->resultHeader=substr($output,0,$info['header_size']);
                $content = substr($output,$info['header_size']);
		if($this->http_code=='200'){
			$this->content=$content;
		}
                
	}
        
	function output(){
		$currentTimeString=gmdate("D, d M Y H:i:s",time());
		$expiredTime=gmdate("D, d M Y H:i:s",(time()+$this->cacheTime));
		
                $doOriginalHeaders = true;
                if($doOriginalHeaders){
                    if($this->IMS){
                            header("HTTP/1.1 304 Not Modified");
                            header("Date: Wed, $currentTimeString GMT");
                            header("Last-Modified: $this->lastModified");
                            header("Server: $this->version");
                    }else{
                            header("HTTP/1.1 200 OK");
                            header("Date: Wed, $currentTimeString GMT");
                            header("Content-Type: ".$this->content_type);
                            header("Last-Modified: $this->lastModified");
                            header("Cache-Control: max-age=$this->cacheTime");
                            header("Expires: $expiredTime GMT");
                            header("Server: $this->version");
                            preg_match("/Set-Cookie:[^\n]*/i",$this->resultHeader,$result);
                            foreach($result as $i=>$value){
                                    header($result[$i]);
                            }
                            preg_match("/Content-Encoding:[^\n]*/i",$this->resultHeader,$result);
                            foreach($result as $i=>$value){
                                    //header($result[$i]);
                            }
                            preg_match("/Transfer-Encoding:[^\n]*/i",$this->resultHeader,$result);
                            foreach($result as $i=>$value){
                                    //header($result[$i]);
                            }
                            echo($this->content);
			    /*
                            if(stristr($this->content, "error")){
                                echo print_r($this->sendPost);
                            }
			    */
                    }
                }
                else{
                    $headerString = $this->resultHeader; //string 
                    $headerArray = explode("\n", $headerString);
                    foreach($headerArray as $privHeader){
                        header($privHeader);
                    }
                    
                    if(stristr($headerString, "Transfer-encoding: chunked")){
                        flush();
                        ob_flush();
                        $i = 0;
                        $maxLen = strlen($this->content);
                        
                        while($i < $maxLen){
                            $endChar = $i + self::chunkSize;
                            if($endChar >= $maxLen){
                                $endChar = $maxLen - 1;
                            }
                            $chunk = substr($this->content, $i, $endChar);
                            $this->dump_chunk($chunk);
                            flush();
                            ob_flush();
                            $i = $i + $endChar;
                        }
                    }
                    else{
                         echo($this->content);
                    }
                    
                    //echo "header: ".print_r($headerArray);
                    //header($this->resultHeader);
                }
                
	}
        
        
        function dump_chunk($chunk) {
            echo sprintf("%x\r\n", strlen($chunk));
            echo $chunk;
            echo "\r\n";
        }
        
        
        function getOutsideHeaders(){
            $headers = array();
            foreach ($_SERVER as $name => $value){ 
                if (substr($name, 0, 5) == 'HTTP_') { 
                    $name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5))))); 
                    $headers[$name] = $value; 
                }elseif ($name == "CONTENT_TYPE") { 
                    $headers["Content-Type"] = $value; 
                }elseif ($name == "CONTENT_LENGTH") { 
                    $headers["Content-Length"] = $value; 
                }elseif(stristr($name, "X-Requested-With")) { 
                    $headers["X-Requested-With"] = $value;
                    $this->XRequestedWith = $value;
                }
            } 
            
            //echo print_r($headers);
  
            $this->outsideHeaders = $headers;
            return $headers;
	}  
    
    
    
    
   
        
}
?>